package com.step.mesh.buffer;

import java.nio.ShortBuffer;

import com.step.mesh.Face;
import com.step.utils.BufferUtils;

/**
 * 顶点索引缓存
 * @author heop
 *
 */
public class FaceBuffer {
	public static final int PROPERTIES_PER_ELEMENT = 3;
	static final int BYTES_PER_PROPERTY = 2;
	private ShortBuffer shortBuffer;
	private int numElements;
	
	/**
	 * 创建面缓存
	 * @param shortBuffer 索引缓存
	 * @param size 面的个数
	 */
	public FaceBuffer(ShortBuffer shortBuffer, int size){
		this.shortBuffer = BufferUtils.newShortBuffer(shortBuffer.limit());
		this.shortBuffer.put(shortBuffer);
		numElements = size;
	}
	
	/**
	 * 创建面缓存
	 * @param maxElements 最大容纳多少个面
	 */
	public FaceBuffer(int maxElements)	{
		shortBuffer = BufferUtils.newShortBuffer(maxElements * PROPERTIES_PER_ELEMENT);//b.asShortBuffer();
	}
	
	/**
	 * 当前已存储的面数 
	 */
	public int size()	{
		return numElements;
	}
	
	
	/**
	 * 最大可容纳的面数
	 */
	public int capacity()	{
		return shortBuffer.capacity() / PROPERTIES_PER_ELEMENT;
	}
	
	/**
	 * 清空缓存
	 */
	public void clear()	{
		shortBuffer.clear();
	}

	/**
	 * 获取面对象
	 * @param index 位置索引
	 * @return
	 */
	public Face getFace(int index){
		shortBuffer.position(index * PROPERTIES_PER_ELEMENT);
		return new Face( shortBuffer.get(), shortBuffer.get(), shortBuffer.get() );
	}
	
	/**
	 * 获取面对象
	 * @param index 位置索引
	 * @param face 获取的面对象
	 */
	public void getFace(int index, Face face)	{
		shortBuffer.position(index * PROPERTIES_PER_ELEMENT);
		face.a = (short)shortBuffer.get();
		face.b = (short)shortBuffer.get();
		face.c = (short)shortBuffer.get();
	}
	
	/**
	 * 获取面第一个顶点序号
	 * @param index 面位置序号
	 * @return
	 */
	public short getA(int index){
		shortBuffer.position(index * PROPERTIES_PER_ELEMENT);
		return (short)shortBuffer.get();
	}
	
	/**
	 * 获取面第二个顶点序号
	 * @param index 面的位置序号
	 * @return
	 */
	public short getB(int index){
		shortBuffer.position(index * PROPERTIES_PER_ELEMENT + 1);
		return (short)shortBuffer.get();
	}
	
	/**
	 * 获取面第三个顶点序号
	 * @param index 面的位置序号
	 * @return
	 */
	public float getC(int index){
		shortBuffer.position(index * PROPERTIES_PER_ELEMENT + 2);
		return (short)shortBuffer.get();
	}
	
	/**
	 * 添加一个面
	 * @param face
	 */
	public void add(Face face)	{
		set( numElements, face );
		numElements++;
	}
	
	public void add(int a, int b, int c) {
		add((short)a, (short)b, (short)c);
	}
	
	
	public void add(short a, short b, short c)	{
		set(numElements, a, b, c);
		numElements++;
	}
	
	public void set(int index, Face face){
		shortBuffer.position(index * PROPERTIES_PER_ELEMENT);
		shortBuffer.put(face.a);
		shortBuffer.put(face.b);
		shortBuffer.put(face.c);
	}

	public void set(int index, short a, short b, short c)	{
		shortBuffer.position(index * PROPERTIES_PER_ELEMENT);
		shortBuffer.put(a);
		shortBuffer.put(b);
		shortBuffer.put(c);
	}
	
	public void setA(int index, short a){
		shortBuffer.position(index * PROPERTIES_PER_ELEMENT);
		shortBuffer.put(a);
	}
	
	public void setB(int index, short b)	{
		shortBuffer.position(index * PROPERTIES_PER_ELEMENT + 1);
		shortBuffer.put(b);
	}
	
	public void setC(int index, short c)	{
		shortBuffer.position(index * PROPERTIES_PER_ELEMENT + 2);
		shortBuffer.put(c);
	}
	
	//	
	public ShortBuffer buffer(){
		return shortBuffer;
	}
	
	public FaceBuffer clone(){
		shortBuffer.position(0);
		FaceBuffer c = new FaceBuffer(shortBuffer, size());
		return c;
	}
	
	// 索引起始位置（部分绘制时有用）
	private int renderOffset = 0;
	// 个数（部分绘制时有用）
	private int renderLength = 1;
	// 是否允许部分绘制
	private boolean enableSubset = false;
	
	/**
	 * 设置部分绘制的起始面位置，必须之前调用enableSubset()方法才有效
	 * @param index
	 */
	public void setOffset(int index){
		if(index < 0 || index >= numElements){
			throw new RuntimeException("FaceBuffer:索引必须小于当前面的数量，并且大于0");
		}
		renderOffset = index;
	}
	
	public int getOffset(){
		return renderOffset;
	}
	
	/**
	 * 绘制多少个三角形面，它必须之前调用setOffset()和enableSubset(true)方法才有效。
	 * 要实现相同功能，推荐使用setRender(int offset, int num)方法。
	 * @param num 面的个数
	 */
	public void setRenderCount(int num){
		renderLength = num;
	}
	
	/**
	 * 设置绘制三角形面的索引起始点和个数，调用该方法，则只有制定的部分面将被绘制。
	 * @param offset
	 * @param num
	 */
	public void setRender(int offset, int num){
		enableSubset = true;
		renderOffset = offset;
		renderLength = num;
	}
	
	public int getRenderCount(){
		return renderLength;
	}
	
	/**
	 * 如果返回true,则绘制从offset开始到绘制renderLength个面。
	 */
	public boolean isEnableSubset(){
		return enableSubset;
	}
	
	/**
	 * 设置是否部分绘制
	 * @param b true,部分绘制。
	 */
	public void enableSubset(boolean b){
		enableSubset = b;
	}
}
